#
#  Interfaces.py
#  TurnShip
#
#  Created by Pete Lord on 22/12/2008.
#  Copyright (c) 2008 __MyCompanyName__. All rights reserved.
#
import pygame, Options, os, ToServer, string
pygame.font.init()

class Interface(list):
    """List to hold all the widgets on-screen"""
    
    def update(self):
        for widget in self:
            widget.update()
    
    def hovering(self, pos):
        """Return widget at (x, y)
        
        If no widget at (x, y) return None"""
        for widget in self:
            # Remove all Tooltip widgets
            if isinstance(widget, Tooltip):
                self.remove(widget)
        x, y = pos
        for widget in self:
            if widget.absolute:
                hovering = widget.hovering((x + self.rect.x, y + self.rect.y))
            else:
                hovering = widget.hovering(pos)
                
            if hovering:
                return hovering
        return None
    
    def clicking(self, pos):
        x, y = pos
        for widget in self:
            if widget.absolute:
                clicking = widget.clicking((x + self.rect.x, y + self.rect.y))
            else:
                clicking = widget.clicking(pos)
                
            if clicking:
                return clicking
        return None
    
class Vertical(list):
    def __init__(self, parent, background=(0, 0, 0, 0)):
        list.__init__(self)
        self.parent = parent
        self.background = background
        self.absolute = False
        self.rect = pygame.Rect(0, 0, 0, 0)
        
    def update(self):
        for widget in self:
            widget.update()
    
    def draw(self):
        # Initialise a new rect
        self.rect.size = (5, 5)
        # Create temporary list to store the widgets to draw
        surfaces = []
        for widget in self:
            widget.rect.topleft = (5, self.rect.height)
            surface, position = widget.draw()
            surfaces.append((surface, position))
            if position.width + 10 > self.rect.width:
                self.rect.width = position.width + 10
            self.rect.height += position.height + 5
        self.surface = pygame.Surface(self.rect.size).convert_alpha()
        self.surface.fill(self.background)
        current = 5
        for surface, position in surfaces:
            self.surface.blit(surface, (5, current))
            current += position.height + 5
        return self.surface, self.rect
    
    def hovering(self, pos):
        x, y = pos
        x -= self.rect.x
        y -= self.rect.y
        pos = x, y
        for widget in self:
            if widget.hovering(pos):
                return widget
        return
    
    def clicking(self, pos):
        x, y = pos
        x -= self.rect.x
        y -= self.rect.y
        pos = x, y
        for widget in self:
            clicking = widget.clicking(pos)
            if clicking:
                return clicking
        return

class Horizontal(Vertical):
    def draw(self):
        # Initialise a new rect
        self.rect.size = (5, 5)
        # Create temporary list to store the widgets to draw
        surfaces = []
        for widget in self:
            widget.rect.topleft = (self.rect.width, 5)
            surface, position = widget.draw()
            surfaces.append((surface, position))
            if position.height + 10 > self.rect.height:
                self.rect.height = position.height + 10
            self.rect.width += position.width + 5
        self.surface = pygame.Surface(self.rect.size).convert_alpha()
        self.surface.fill(self.background)
        current = 5
        for surface, position in surfaces:
            self.surface.blit(surface, (current, 5))
            current += position.width + 5
        return self.surface, self.rect
        

class ShipInfoContainer(Horizontal):
    def __init__(self, parent, ship):
        Horizontal.__init__(self, parent, (0, 0, 0, 100))
        self.ship = ship
        self.append(ShipInfo(self, ship))
        if ship == ship.entities.selected:
            if ship.player == ship.entities.players.turn:
                if ship.player == ship.entities.player.key():
                    self.append(Vertical(self))
                    # Add new Weapon widgets for the currently selected ship
                    self[-1].append(Weapon(self[-1], ship.entities.graphics, ship, 0, ship.entities.server))
                    self[-1].append(Weapon(self[-1], ship.entities.graphics, ship, 1, ship.entities.server))
        self.absolute = True
        self.draw()
        self.update()
    
    def update(self):
        x, y = self.ship.screen_location()
        self.rect.topleft = (x - (self.rect.width - Options.TILE_WIDTH[Options.ZOOM_LEVEL]) / 2, y - self.rect.height)
        Horizontal.update(self)

class Widget(object):
    """Baseclass for widgets"""
    
    font = pygame.font.Font(pygame.font.match_font('georgia'), 12)
    # Set to true to draw widget at absolute (x, y)
    # i.e., the widget will scroll with screen
    absolute = False
    
    def __init__(self, parent, rect):
        self.parent = parent
        self.rect = rect
    
    def clicking(self, pos):
        if self.rect.collidepoint(pos):
            return self.click(pos)
        return
    
    def click(self, pos):
        """Widget.click should return False if it doesn't grab focus but
        True if it does"""
        return False
        
    def draw(self):
        return self.surface, self.rect
        
    def hovering(self, pos):
        # If pos is within rect
        if self.rect.collidepoint(pos):
            # Do stuff
            self.hover(pos)
            return self
        # If pos isn't within rect
        return
        
    def hover(self, pos):
        """Run when the widget is hovered over"""
        return
    
    def update(self):
        return
        
class Text(Widget):
    """Simple widget which renders text"""
    def __init__(self, parent, text):
        self.text = text
        self.parent = parent
        self.render()
        
    def render(self):
        self.surface = self.font.render(self.text, True, (255, 255, 255))
        self.rect = self.surface.get_rect()

class TextInput(Text):
    def __init__(self, parent):
        Text.__init__(self, parent, "")
    
    def click(self, pos):
        return True
    
    def enter(self):
        return
    
    def esc(self):
        return
    
    def event(self, event):
        #if pygame.key.name(event.key) in string.printable:
        if pygame.key.name(event.key) in string.letters + string.digits + "'.," or event.key == pygame.K_SPACE:
            char = chr(event.key)
            for mod in (pygame.KMOD_LSHIFT, pygame.KMOD_RSHIFT, pygame.KMOD_SHIFT, pygame.KMOD_CAPS):
                if event.mod & mod != 0:
                    char = char.upper()
            self.text += char
            self.render()
        elif event.key == pygame.K_BACKSPACE:
            self.text = self.text[:-1]
            self.render()
        elif event.key == pygame.K_RETURN:
            self.enter()
        elif event.key == pygame.K_ESCAPE:
            self.esc()

class MessageInput(TextInput):
    def __init__(self, parent, server):
        TextInput.__init__(self, parent)
        self.server = server
    
    def enter(self):
        # Don't send empty messages
        if len(self.text) > 0:
            self.server.send(ToServer.Say(self.text))
        self.esc()
    
    def esc(self):
        self.parent.parent.remove(self.parent)
        self.parent.remove(self)
        

class MessageBox(Widget):
    """Simple messagebox widget which disappears when clicked"""
    def __init__(self, parent, message, place):
        self.message = message
        self.rect = pygame.Rect(place, (0, 0))
        self.render()
        Widget.__init__(self, parent, pygame.Rect(place, self.surface.get_size()))
            
    def click(self, pos):
        self.parent.remove(self)

    def render(self):
        padding = 10
        render = self.font.render(self.message, True, (255, 255, 255))
        width, height = render.get_size()
        width += padding * 2
        height += padding * 2
        self.surface = pygame.Surface((width, height)).convert_alpha()
        self.surface.fill((0, 0, 0, 100))
        self.surface.blit(render, (padding, padding))
        self.rect.width, self.rect.height = width, height
        
class Tooltip(MessageBox):
    def hovering(self, pos):
        return False

class TimedBox(MessageBox):
    def __init__(self, parent, message):
        MessageBox.__init__(self, parent, message, (-5, -5))
        self.timeout = 0
        for widget in parent:
            if widget != self:
                if isinstance(widget, TimedBox):
                    widget.rect.move_ip(0, -self.rect.height - 5)
    
    def update(self):
        # If we've reached our final hour
        if self.timeout == Options.MESSAGEBOX_TIMEOUT:
            # Goodbye!
            self.parent.remove(self)
        self.timeout += 1
        
class TurnBox(Widget):
    def __init__(self, parent, entities):
        self.entities = entities
        self.textures = []
        for i in range(1, 5):
            self.textures.append(entities.graphics[os.path.join("Data", "p" + str(i) + "turn.png")])
        Widget.__init__(self, parent, pygame.Rect((5, 5), self.textures[0].get_size()))
        
    def click(self, pos):
        # End turn (next player)
        self.entities.server.send(ToServer.EndTurn())
        return False
        
    def hover(self, pos):
        """Run when the widget is hovered over"""
        return
    
    def draw(self):
        return self.textures[(self.entities.players[self.entities.players.turn].number - self.entities.player.number) % len(self.entities.players)], self.rect
        
class Weapon(Widget):
    def __init__(self, parent, graphics, ship, weapon, server):
        x, y = ship.shadow_location()
        self.surface = graphics[os.path.join("Data", "Cannon" + chr(65 + weapon) + ".png")]
        Widget.__init__(self, parent, pygame.Rect((0, 0), self.surface.get_size()))
        self.ship = ship
        self.weapon = weapon
        self.server = server
        self.absolute = False
    
    def hover(self, pos):
        """Run when the widget is hovered over"""
        # Set the tiles to draw
        self.ship.entities.targets = self.ship.weapons[self.weapon].targets
    
    def click(self, pos):
        self.server.send(ToServer.Fire(self.ship, self.weapon))
        return False
        
    def update(self):
        x, y = self.ship.shadow_location()
        self.rect.topleft = (x + self.weapon * (self.rect.width + 5), y + Options.TILE_HEIGHT[Options.ZOOM_LEVEL])

class ShipInfo(Widget):
    """Simple widget to display info on the selected ship"""
    def __init__(self, parent, ship):
        self.absolute = True
        self.ship = ship
        self.padding = 10
        self.update()
        Widget.__init__(self, parent, self.rect)

    def hovering(self, pos):
        # return None to allow click-through
        return

    def update(self):
        try:
            info = self.info()
            renders = []
            width, height = 0, 0
            for line in info:
                renders.append(self.font.render(line, True, (255, 255, 255)))
                if renders[-1].get_width() > width:
                    width = renders[-1].get_width()
                height += renders[-1].get_height()
            width += self.padding * 2
            height += self.padding * 2
            self.surface = pygame.Surface((width, height)).convert_alpha()
            self.surface.fill((0, 0, 0, 0))
            y = self.padding
            for render in renders:
                self.surface.blit(render, ((width - render.get_width()) / 2, y))
                y += render.get_height()
            self.rect = pygame.Rect(0, 0, width, height)
        except:
            self.parent.remove(self)
    
    def info(self):
        for player in self.ship.entities.players.values():
            if self.ship.key() in player.ships:
                if player == self.ship.entities.player:
                    name = "You"
                else:
                    name = player.name
        return ["Class: " + str(self.ship.__class__.__name__),
                "Player: " + name,
                "",
                "SU: " + str(self.ship.steam) + "/" + str(self.ship.steam_max) + "/+" + str(self.ship.steam_prod),
                "SI: " + str(self.ship.health) + "/" + str(self.ship.health_max),
                #"SI: " + str(int(float(self.ship.health) * 100 / self.ship.health_max)) + "%",
               ]

class Compass(Widget):
    def __init__(self, parent, entities):
        self.surface = entities.graphics[os.path.join("Data", "Compass.png")]
        Widget.__init__(self, parent, pygame.Rect((-5, 5), self.surface.get_size()))
        
    def draw(self):
        return self.surface, self.rect

    def hovering(self, pos):
        return None
